package com.lucifer.d.security.transfer;

import com.alibaba.fastjson.JSON;
import com.lucifer.d.security.annotation.model.RoleId;
import com.lucifer.d.security.annotation.model.RoleName;
import com.lucifer.d.security.annotation.model.UserId;
import com.lucifer.d.security.annotation.model.UserName;
import com.lucifer.d.security.exception.LuciferSecurityException;
import com.lucifer.d.security.model.SecurityConfigModel;
import com.lucifer.d.security.util.ReflectUtil;
import com.lucifer.d.security.util.TokenDecode;
import com.lucifer.d.util.RedissonUtil;
import com.lucifer.d.util.SelfEncryption;
import com.lucifer.d.util.SnowflakeIdWorker;
import com.lucifer.d.util.StringUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Data;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * 用户信息及Token验证
 *
 * @author Lucifer
 */
@Data
public class UserTransfer {

    /**
     * token模板
     */
    private final static String tokenTemplate = "Authentication:Basic 123456789";

    /**
     * token对标前缀（后优化为配置）
     */
    private String tokenLoginVerify = "token:verify:";

    /**
     * token加密盐（后优化为配置）
     */
    private String salt = "lucifer-security";

    @Autowired
    private RedissonClient redissonClient;

    private HttpServletRequest request;

    private SecurityConfigModel securityConfigModel;

    public UserTransfer(SecurityConfigModel securityConfigModel) {
        if (securityConfigModel.getOnSecurity()){
            try {
                // 权限过滤载体配置验证
                if (securityConfigModel.getAuthMsg() == null){
                    if (!StringUtil.isEmpty(securityConfigModel.getAuthMsgClass())){
                        securityConfigModel.setAuthMsg(Class.forName(securityConfigModel.getAuthMsgClass()));
                    }else {
                        throw new LuciferSecurityException("权限过滤载体配置错误");
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        this.securityConfigModel = securityConfigModel;
    }

    public void setReq(HttpServletRequest request){
        this.request = request;
    }

    /**
     * 通过security黑盒子获取用户信息
     *
     * @return
     */
    public Object getSecurityUser(){
        // 获取request
        request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        // 获取前端请求参数
        String token = request.getHeader(securityConfigModel.getTokenHead());
        if (StringUtil.isEmpty(token)){
            return null;
        }else {
            try {
                if (!StringUtil.isEmpty(token)){
                    token = token.substring(securityConfigModel.getTokenPrefix().length());
                }
                // FIXME 验证是否直接放行token
                if (!StringUtil.isEmpty(securityConfigModel.getPassToken()) && token.equals(securityConfigModel.getPassToken())){
                    Object user = securityConfigModel.getAuthMsg().newInstance();
                    ReflectUtil.setValueOnReflect(user, UserId.class, securityConfigModel.getPassRoleId());
                    ReflectUtil.setValueOnReflect(user, UserName.class, securityConfigModel.getPassRoleName());
                    ReflectUtil.setValueOnReflect(user, RoleId.class, securityConfigModel.getPassRoleId());
                    ReflectUtil.setValueOnReflect(user, RoleName.class, securityConfigModel.getPassRoleName());
                    return user;
                }
                // TODO 从缓存中获取token对应的用户信息
                Object user = TokenDecode.tokenDecode(securityConfigModel.getAuthMsg(), securityConfigModel.getTokenPrefix(), token, redissonClient, securityConfigModel.getLoginValidUser());
                return user;
            }catch (Exception e){
                e.printStackTrace();
                return null;
            }
        }
    }

    /**
     * 通过security黑盒子获取用户信息
     *
     * @return
     */
    public Object getSecurityUser(ServerHttpRequest request){
        // 获取前端请求参数
        String token = request.getHeaders().getFirst(securityConfigModel.getTokenHead());
        if (StringUtil.isEmpty(token)){
            return null;
        }else {
            try {
                if (!StringUtil.isEmpty(token)){
                    token = token.substring(securityConfigModel.getTokenPrefix().length());
                }
                // FIXME 验证是否直接放行token
                if (!StringUtil.isEmpty(securityConfigModel.getPassToken()) && token.equals(securityConfigModel.getPassToken())){
                    Object user = securityConfigModel.getAuthMsg().newInstance();
                    ReflectUtil.setValueOnReflect(user, UserId.class, securityConfigModel.getPassRoleId());
                    ReflectUtil.setValueOnReflect(user, UserName.class, securityConfigModel.getPassRoleName());
                    ReflectUtil.setValueOnReflect(user, RoleId.class, securityConfigModel.getPassRoleId());
                    ReflectUtil.setValueOnReflect(user, RoleName.class, securityConfigModel.getPassRoleName());
                    return user;
                }
                // TODO 从缓存中获取token对应的用户信息
                Object user = TokenDecode.tokenDecode(securityConfigModel.getAuthMsg(), securityConfigModel.getTokenPrefix(), token, redissonClient, securityConfigModel.getLoginValidUser());
                return user;
            }catch (Exception e){
                e.printStackTrace();
                return null;
            }
        }
    }

    /**
     * 通过security黑盒子获取指定用户信息
     *
     * @return
     */
    public Object getSecurityUser(String token){
        // 获取前端请求参数
        if (StringUtil.isEmpty(token)){
            return null;
        }else {
            try {
                if (!StringUtil.isEmpty(token)){
                    token = token.substring(securityConfigModel.getTokenPrefix().length());
                }
                // FIXME 验证是否直接放行token
                if (!StringUtil.isEmpty(securityConfigModel.getPassToken()) && token.equals(securityConfigModel.getPassToken())){
                    Object user = securityConfigModel.getAuthMsg().newInstance();
                    ReflectUtil.setValueOnReflect(user, UserId.class, securityConfigModel.getPassRoleId());
                    ReflectUtil.setValueOnReflect(user, UserName.class, securityConfigModel.getPassRoleName());
                    ReflectUtil.setValueOnReflect(user, RoleId.class, securityConfigModel.getPassRoleId());
                    ReflectUtil.setValueOnReflect(user, RoleName.class, securityConfigModel.getPassRoleName());
                    return user;
                }
                // TODO 从缓存中获取token对应的用户信息
                Object user = TokenDecode.tokenDecode(securityConfigModel.getAuthMsg(), securityConfigModel.getTokenPrefix(), token, redissonClient, securityConfigModel.getLoginValidUser());
                return user;
            }catch (Exception e){
                e.printStackTrace();
                return null;
            }
        }
    }

    /**
     * 系统通行用默认user
     *
     * @return
     */
    public Object getSystemUser() throws Exception {
        Object user = securityConfigModel.getAuthMsg().newInstance();
        ReflectUtil.setValueOnReflect(user, UserId.class, securityConfigModel.getPassRoleId());
        ReflectUtil.setValueOnReflect(user, UserName.class, securityConfigModel.getPassRoleName());
        ReflectUtil.setValueOnReflect(user, RoleId.class, securityConfigModel.getPassRoleId());
        ReflectUtil.setValueOnReflect(user, RoleName.class, securityConfigModel.getPassRoleName());
        return user;
    }

    /**
     * 刷新用户黑盒数据
     *
     * @param user
     */
    public void refresh(Object user) throws Exception{
        // 获取request
        request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        setSecurity(user, request.getHeader(securityConfigModel.getTokenHead()));
    }

    /**
     * 黑盒子缓存部署（有时效，自定时效，秒级）
     *
     * @param user
     * @param token
     */
    public void setSecurity(Object user, String token, Long time) throws Exception{
        RedissonUtil.set(redissonClient, token, JSON.toJSONString(user), time);
        // 记录用户对应token，指定登出用
        RedissonUtil.set(redissonClient, tokenLoginVerify + ReflectUtil.getObjFieldOnReflect(user, UserId.class), SelfEncryption.encode(token, salt), time);
    }

    /**
     * 黑盒子缓存部署（有时效）
     *
     * @param user
     * @param token
     */
    public void setSecurity(Object user, String token) throws Exception{
        // 有效时间换算
        Integer time = securityConfigModel.getLoginValidUser() * 24 * 60 * 60;
        RedissonUtil.set(redissonClient, token, JSON.toJSONString(user), time);
        // 记录用户对应token，指定登出用
        RedissonUtil.set(redissonClient, tokenLoginVerify + ReflectUtil.getObjFieldOnReflect(user, UserId.class), SelfEncryption.encode(token, salt), time);
    }

    /**
     * 黑盒子缓存部署（无时效）
     *
     * @param user
     * @param token
     */
    public void setSecurityOnInfinite(Object user, String token) throws Exception{
        // token无限期有效
        RedissonUtil.set(redissonClient, token, JSON.toJSONString(user));
        // 记录用户对应token，指定登出用
        RedissonUtil.set(redissonClient, tokenLoginVerify + ReflectUtil.getObjFieldOnReflect(user, UserId.class), SelfEncryption.encode(token, salt));
    }

    /**
     * 登录注销（默认前缀：Basic ）
     */
    public void logout(){
        // 获取request
        request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        // 获取前端请求参数
        String token = request.getHeader(securityConfigModel.getTokenHead());
        RedissonUtil.delete(redissonClient, token);
    }

    /**
     * 全账户登出
     */
    public void logoutAll(){
        RedissonUtil.deleteAny(redissonClient, securityConfigModel.getTokenPrefix() + "*");
    }

    /**
     * 指定账户登出
     */
    public void logoutUser(String userId){
        String token = RedissonUtil.getAndDelete(redissonClient, tokenLoginVerify + userId);
        if (!StringUtil.isEmpty(token)){
            RedissonUtil.delete(redissonClient, SelfEncryption.decode(token, salt));
        }
    }

    /**
     * token产生
     *
     * @param request
     * @param response
     * @return
     */
    public String tokenCreate(HttpServletRequest request, HttpServletResponse response){
        StringBuffer token = new StringBuffer(securityConfigModel.getTokenPrefix());
        if (!StringUtil.isEmpty(securityConfigModel.getSource())){
            token.append(request.getHeader(securityConfigModel.getSource()) + " ");
        }
        token.append(SnowflakeIdWorker.nextId());
        response.setHeader(securityConfigModel.getTokenHead(), token.toString());
        return token.toString();
    }

}
